<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第9章 思维转变与大型项目管理 | 深入理解Vue.js实战</title>
    <meta name="generator" content="VuePress 1.9.7">
    
    <meta name="description" content="作者：被删">
    
    <link rel="preload" href="/vue-ebook/assets/css/0.styles.2728a2da.css" as="style"><link rel="preload" href="/vue-ebook/assets/js/app.a856ee15.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/2.2a4d101b.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/3.9083e877.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/23.46caffca.js" as="script">
    <link rel="stylesheet" href="/vue-ebook/assets/css/0.styles.2728a2da.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue-ebook/" class="home-link router-link-active"><!----> <span class="site-name">深入理解Vue.js实战</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前言</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/0.html" class="sidebar-link">前端框架的出现</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>第一部分 Vue快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/1.html" class="sidebar-link">第1章 Vue 框架介绍</a></li><li><a href="/vue-ebook/vue-ebook/2.html" class="sidebar-link">第2章 Vue 环境快速搭建</a></li><li><a href="/vue-ebook/vue-ebook/3.html" class="sidebar-link">第3章 Vue 基础介绍</a></li><li><a href="/vue-ebook/vue-ebook/4.html" class="sidebar-link">第4章 Vue 组件的使用</a></li><li><a href="/vue-ebook/vue-ebook/5.html" class="sidebar-link">第5章 常用指令和自定义指令</a></li><li><a href="/vue-ebook/vue-ebook/6.html" class="sidebar-link">第6章 Vue 动画</a></li><li><a href="/vue-ebook/vue-ebook/7.html" class="sidebar-link">第7章 Vue Router 路由搭建应用</a></li><li><a href="/vue-ebook/vue-ebook/8.html" class="sidebar-link">第8章 实战：Todo List 从组件到应用</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>第二部分 Vue的正确使用方式</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/9.html" aria-current="page" class="active sidebar-link">第9章 思维转变与大型项目管理</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/9.html#_9-1-编码思维转变" class="sidebar-link">9.1 编码思维转变</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/9.html#_9-2-大型应用管理" class="sidebar-link">9.2 大型应用管理</a></li></ul></li><li><a href="/vue-ebook/vue-ebook/10.html" class="sidebar-link">第10章 如何正确地进行抽象</a></li><li><a href="/vue-ebook/vue-ebook/11.html" class="sidebar-link">第11章 全局数据管理与 Vuex</a></li><li><a href="/vue-ebook/vue-ebook/12.html" class="sidebar-link">第12章 实战：三天开发一个管理端</a></li><li><a href="/vue-ebook/vue-ebook/13.html" class="sidebar-link">第13章 实战：表单配置化实现</a></li><li><a href="/vue-ebook/vue-ebook/14.html" class="sidebar-link">第14章 实战：使用 Webpack 或 Vue CLI 搭建多页应用</a></li><li><a href="/vue-ebook/vue-ebook/15.html" class="sidebar-link">第15章 Vue 周边拓展</a></li><li><a href="/vue-ebook/vue-ebook/16.html" class="sidebar-link">第16章 关于 Vue 3.0</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>后记</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/99.html" class="sidebar-link">关于框架选型</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="第9章-思维转变与大型项目管理"><a href="#第9章-思维转变与大型项目管理" class="header-anchor">#</a> 第9章 思维转变与大型项目管理</h1> <p>这些年来前端发展进步了很多，不管是工具、框架的丰富，还是前端在各个领域的应用拓展，越来越多的人开始加入前端大军。而随着拥有的能力越来越多，如果我们不在适当的时候进行梳理和调整，越到后面就越抽不出时间进行思考，因为已经被死亡代码（俗称屎山）埋没了。为了避免这种事情的发生，我也常常进行一些思考和自我调整，一起分享给你们。</p> <h2 id="_9-1-编码思维转变"><a href="#_9-1-编码思维转变" class="header-anchor">#</a> 9.1 编码思维转变</h2> <p>首先介绍事件驱动和数据驱动两种编码思维模式，其实两种写码方式它和你使用 jQuery 还是使用 Vue 等框架并没有多大的关系，更多会在于设计代码时的一个思考方式。</p> <p>但事实上当年我在从 jQuery 切换到 AngularJS 的时候，也是常常满屏的疑惑，不知道从何下手。而事件驱动和数据驱动的思维调整，也是在这一个过渡过程体会比较深刻，所以这里还是会结合 jQuery 和 Vue 来讲解一下这样的转变。</p> <p>我们先来看看事件驱动的编码方式。</p> <h3 id="_9-1-1-事件驱动"><a href="#_9-1-1-事件驱动" class="header-anchor">#</a> 9.1.1 事件驱动</h3> <p>由于前端是页面交互出身的，运作模式也是基于 I/O 模式。你知道为什么 JavaScript 是单线程的吗？其实更多是因为对页面交互的同步处理。作为浏览器脚本语言，JavaScript 的主要用途是与用户互动，以及操作 DOM，若是多线程会导致严重的同步问题。</p> <p>为什么这么说呢？我们可以从 GUI（图形用户界面）来讲起。</p> <h4 id="gui-与事件"><a href="#gui-与事件" class="header-anchor">#</a> GUI 与事件</h4> <p>GUI（图形用户界面）与事件驱动的渊源可谓不浅。GUI 应用程序的特点是注重与用户的交互，因此程序的执行取决于与用户的实时交互情况，大部分的程序执行需要等到用户的交互动作发生之后。由于用户的输入频率并不高，若不停轮询获取用户输入（点像 ajax 轮询），这样的方式存在以下问题：<br>
(1) 资源利用率低。<br>
(2) 不能真正做到及时同步。</p> <p>由于 GUI 程序的执行流程由用户控制，并且不可预期，为了适应这种特点，我们通常采用事件驱动的编程方法。程序对事件的响应，其实就是调用预先编制好的代码来对事件进行处理。</p> <p>如果 Javascript 完全使用同步的单线程方式来执行，我们就无法对多个事件进行监听。除此之外，我们的页面交互就会变得很慢，还会有很大一部分的等待时间，造成很多资源浪费。所以 Javascript 是异步的，支持多个事件的并发，而 JavaScript 的并发模型基于“事件循环”。在 Javascript 中，主线程从&quot;任务队列&quot;中读取事件，这个过程是循环不断的，整个的这种运行机制又称为 Event Loop（事件循环）。</p> <p>在 GUI 的使用场景和并发的 Javascript 设计下，我们写代码的时候也会代入这样的思维：<strong>用户输入 =&gt; 事件响应 =&gt; 代码运行 =&gt; 刷新页面状态</strong>。于是乎，刚开始写页面功能的思路如下：<br>
(1) 开发静态页面。<br>
(2) 添加事件监听，包括用户输入、http 请求、定时器触发等事件。<br>
(3) 针对不同事件，编写不同的处理逻辑，包括获取事件状态/输入、计算并更新状态等。<br>
(4) 根据计算后的数据状态，重新渲染页面。</p> <p>通俗地说，事件驱动思维是从事件响应出发，来完成应用的设计和编程。事件驱动的编码方式，在 jQuery 提供了链式调用、方便的<code>$()</code>元素选择、<code>on()</code>事件监听之后进入了热潮，我们经常会写这样的代码：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 某个父元素上监听多个子节点的事件并处理</span>
<span class="token comment">// setLength 函数用来限制长度</span>
someDom
  <span class="token comment">// 子节点 A 是输入框，样式为 classA</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;keyup&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;.classA&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    inputObject<span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token function">setLength</span><span class="token punctuation">(</span>ev<span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token comment">// 子节点 B 也是输入框，样式为 classB</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;keyup&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;.classB&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    inputObject<span class="token punctuation">.</span>b <span class="token operator">=</span> <span class="token function">setLength</span><span class="token punctuation">(</span>ev<span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token comment">// 子节点 C 也是输入框，样式为 classC</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;keyup&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;.classC&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    inputObject<span class="token punctuation">.</span>c <span class="token operator">=</span> <span class="token function">setLength</span><span class="token punctuation">(</span>ev<span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token comment">// 子节点 D 为下拉列表，样式为 classD</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;change&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;.classD&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    inputObject<span class="token punctuation">.</span>d <span class="token operator">=</span> ev<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>在 jQuery 的帮助下，事件绑定写起来真的太爽啦，虽然可读性和维护性上都有缺陷，但在当时也是性价比很高的开发方式了。所以当时很多开发者会选择（或是不自主地）使用事件驱动方式来写代码。</p> <h4 id="事件驱动的流程"><a href="#事件驱动的流程" class="header-anchor">#</a> 事件驱动的流程</h4> <p>事件驱动其实是前端开发中最容易理解的编码方式，例如我们写一个提交表单的页面，用事件驱动的方式来写的话，会是这样一个流程：</p> <p><strong>(1) 编写静态页面。</strong></p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 实现静态页面 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span>
  Name:
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name-value<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name-input<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
  Email:
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email-value<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email<span class="token punctuation">&quot;</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email<span class="token punctuation">&quot;</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email-input<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p><strong>(2) 给对应的元素绑定对应的事件。</strong></p> <p>例如给 input 输入框绑定输入事件，在前端页面中绑定事件监听通过<code>addEventListener</code>来实现：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> nameInputEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;name-input&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> emailInputEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;email-input&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 监听输入事件，此时 updateValue 函数未定义</span>
nameInputEl<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;input&quot;</span><span class="token punctuation">,</span> updateNameValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
emailInputEl<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;input&quot;</span><span class="token punctuation">,</span> updateEmailValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><strong>(3) 事件触发时，更新页面内容。</strong></p> <p>我们给元素绑定了事件监听之后，在事件触发的时候，我们需要进行相关逻辑的处理（发起请求、更新页面内容等），这里我们将用户输入的内容更新到页面中展示：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> nameValueEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;name-value&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> emailValueEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;email-value&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 定义 updateValue 函数，用来更新页面内容</span>
<span class="token keyword">function</span> <span class="token function">updateNameValue</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  nameValueEl<span class="token punctuation">.</span>innerText <span class="token operator">=</span> e<span class="token punctuation">.</span>srcElement<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">updateEmailValue</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  emailValueEl<span class="token punctuation">.</span>innerText <span class="token operator">=</span> e<span class="token punctuation">.</span>srcElement<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>以上这个流程，是很常见的前端编码思维，我们称之为<strong>事件驱动</strong>模式。如果使用了 Vue，也是可以很容易用事件驱动的方式这样写代码：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 1. 绘制 HTML --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    Name:
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>{{ name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 2. 使用 v-on 绑定事件，这里绑定 updateValue 方法 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span> <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span> <span class="token attr-name"><span class="token namespace">v-on:</span>change</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>updateValue<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token comment">&lt;!-- 上面 input 可以简写为： --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token comment">// 3. change 事件触发时，更新数据</span>
      <span class="token function">updateValue</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>Vue 帮我们省去了元素选择、HTML 拼接并更新等这些工作，同时直接在模板上绑定的方式也简化了（使用<code>v-on:</code>或者<code>@</code>），方便开发者阅读和理解。</p> <p>我们再来回顾下事件驱动的方式：<br>
(1) 开发静态页面。<br>
(2) 在对应的元素上绑定事件。<br>
(3) 实现被绑定的事件功能，例如获取数据、更新页面等。</p> <p>整个思考的链路在于<strong>触发了怎样的操作</strong>和<strong>这个操作会导致什么后果（即需要做怎样的处理）</strong>，事件驱动的思维方式都是围绕“操作”（在前端语言中，也就是“事件”），我们跟随着“操作”的链路来实现代码编写。</p> <p>如今前端页面交互也越来越复杂，我们在设计功能的时候，也常常需要使用抽象的能力。作为程序员，我们最常用的抽象方式就是数据抽象，而前端的界面、组件、配置等，都可以抽象成数据表达。关于怎么进行抽象，<a href="/vue-ebook/vue-ebook/10.html">《第10章 如何正确地进行抽象》</a>内容会详细介绍。</p> <p>我们看看数据驱动的思维方式是怎样的。</p> <h3 id="_9-1-2-数据驱动"><a href="#_9-1-2-数据驱动" class="header-anchor">#</a> 9.1.2 数据驱动</h3> <p>其实不管是生活中还是工作中，几乎所有的事物我们都可以抽象为数据。像游戏里面的角色、物品、经验值、天气、时间等等，都是数据。游戏其实也算是对真实世界抽象的一种，而抽象之后，最终都可呈现为数据。</p> <p>如果要对事件驱动和数据驱动进行直观的比较，其实最大的转变是，以前会把组件视为 DOM，把事件/逻辑处理视为 Javascript，把样式视为 CSS。而当转换思维方式之后，组件、事件、逻辑处理、样式都是一份数据，我们只需要把数据的状态和转换设计好，剩下的实现则由具现方式（模版引擎、事件机制等）来实现。</p> <h4 id="数据驱动的流程"><a href="#数据驱动的流程" class="header-anchor">#</a> 数据驱动的流程</h4> <p>既然前面介绍了事件模型一般的编码流程，我们再来看看，同样的写一个提交表单的页面，用数据驱动的方式来写的话，会是下面这样的步骤过程。</p> <p><strong>(1) 设计数据结构。</strong></p> <p>首先我们需要，将页面中会变化和不会变化的内容隔离开，然后对其中会变化的内容进行抽象，再根据抽象结果来设计数据结构。例如这里的表单，可变的部分包括两个输入框、两处展示输入框内容的文字。但其实涉的数据只有两个，一个是名字<code>name</code>，另外一个是邮件<code>email</code>，都可以用字符串表示：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 包括一个 name 和 一个 email 的值</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
      <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p><strong>(2) 完成静态页面，同时把数据和事件绑定到页面中。</strong></p> <p>接下来我们把静态页面开发出来，然后将步骤(1)中的数据绑定到页面中需要使用/展示的地方，同时在一些事件触发的元素上绑定对应的方法：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span>
  Name:
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>{{ name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name"><span class="token namespace">v-on:</span>input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>updateNameValue<span class="token punctuation">&quot;</span></span>
  <span class="token punctuation">/&gt;</span></span>
  Email:
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>{{ email }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
    <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name"><span class="token namespace">v-bind:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>email<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name"><span class="token namespace">v-on:</span>input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>updateEmailValue<span class="token punctuation">&quot;</span></span>
  <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p><strong>(3) 事件绑定的方法（methods）中，补充相应的逻辑处理。</strong></p> <p>我们在第(2)步中绑定了一下事件监听，主要是两个输入框<code>v-on:input</code>绑定的输入事件，我们需要在用户输入的同时更新到<code>data</code>中：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
      <span class="token literal-property property">email</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 绑定 input 事件，获取到输入值，设置到对应的数据中</span>
    <span class="token function">updateNameValue</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">updateEmailValue</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>email <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>我们在设置数据（<code>this.name = event.target.value</code>）的时候，Vue 会自动帮我们更新页面中绑定该数据的内容（<code></code>和<code></code>处），我们就不用自己手动获取元素然后更新节点内容了。</p> <p>其实我们也可以先开发静态模板，然后根据可变的内容来设计数据结构。事件驱动和数据驱动一个很重要的区别在于，我们是从每个事件的触发（“操作”）为中心来设计我们的代码，还是<strong>以数据为中心</strong>，接收事件触发和更新数据状态的方式来写代码。</p> <p>我们再来详细地对比一下。</p> <h3 id="_9-1-3-数据驱动和事件驱动"><a href="#_9-1-3-数据驱动和事件驱动" class="header-anchor">#</a> 9.1.3 数据驱动和事件驱动</h3> <p>这里或许你们会有些疑问，看起来只是写代码的顺序不一样而已，甚至写代码的顺序都是一样的，那事件驱动和数据驱动的区别在哪？一个很有用的区别在于，从事件驱动转换到数据驱动思维后，我们在编程实现的过程中，更多的是思考数据状态的维护和处理，而无需过于考虑 UI 的变化和事件的监听，即使我们页面全部重构了，影响到的只有模板中绑定的部分，重新绑定一下就可以了。</p> <p>使用数据驱动来写代码会强迫开发者有一个前置条件，你会需要去设计一个数据结构，或者也可以称之为一个模型。在代码开发前的数据设计会有什么好处呢？</p> <h4 id="数据的获取和修改"><a href="#数据的获取和修改" class="header-anchor">#</a> 数据的获取和修改</h4> <p>我们在设计数据的时候，会进行将页面抽象成数据的一个步骤，例如一个表单里的内容可以抽象成一个对象，而一个列表中的内容可以表达成一个由对象组成的数组。</p> <p>在 Vue 中，我们可以直接将数据绑定到页面元素中，而当这些内容变动的时候，我们只需要按照设计的数据格式来更新数据就可以。例如，我们新建了一个表单，然后在从后台拉取数据、获取填写的内容进行校验并提交到后台、提交成功后清空已填写内容等，可以这么实现：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>姓名<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formInfo.name<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>手机号码<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>tel<span class="token punctuation">&quot;</span></span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formInfo.phone<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>家庭地址<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formInfo.address<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>textarea</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>提交<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        <span class="token comment">// 表单内容信息</span>
        <span class="token literal-property property">formInfo</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
          <span class="token literal-property property">phone</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
          <span class="token literal-property property">address</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 从后台拉取数据</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getPhoneInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token function">getPhoneInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// request 为一个请求库示例，返回 Promise</span>
        <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">&quot;test&quot;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// 获取数据，并填入</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>phoneInfo <span class="token operator">=</span> res<span class="token punctuation">.</span>phone_info<span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function">submit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 提取填写的内容并提交</span>
        <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> phone<span class="token punctuation">,</span> address <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>phoneInfo<span class="token punctuation">;</span>
        <span class="token comment">// 这里也可以进行一些表单验证，此处略</span>
        <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">&quot;test&quot;</span><span class="token punctuation">,</span>
          <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            name<span class="token punctuation">,</span>
            phone<span class="token punctuation">,</span>
            address
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token comment">// 成功后可以清空</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>phoneInfo <span class="token operator">=</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
            <span class="token literal-property property">phone</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
            <span class="token literal-property property">address</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
          <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>在这整个过程中（获取数据并更新到页面、获取用户输入的内容、清空输入框内容），我们只需要获取和修改<code>phoneInfo</code>这个数据就可以了。而 Vue 框架会帮我们完成从页面元素获取数据，以及将数据更新到页面展示中这些工作。那是否意味着使用 jQuery 就不可以这样做了呢？并不是，如果要在 jQuery 中使用数据驱动，我们需要自己去实现从页面获取数据、更新到页面中这样的逻辑，例如:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">getPhoneInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 获取数据并返回</span>
  <span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> phone <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#phone&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> address <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#address&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    name<span class="token punctuation">,</span>
    phone<span class="token punctuation">,</span>
    address
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">setPhoneInfo</span><span class="token punctuation">(</span><span class="token parameter">phoneInfo</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> phone<span class="token punctuation">,</span> address <span class="token punctuation">}</span> <span class="token operator">=</span> phoneInfo<span class="token punctuation">;</span>
  <span class="token comment">// 给元素设置数据</span>
  <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#phone&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span>phone<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#address&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">val</span><span class="token punctuation">(</span>address<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>这样，我们在 jQuery 中实现以上逻辑应该是这样：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>姓名<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>手机号码<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>tel<span class="token punctuation">&quot;</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>phone<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><span class="token punctuation">&gt;</span></span>家庭地址<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>textarea</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>address<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>textarea</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>提交<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token comment">// 页面加载就发起请求</span>
  <span class="token function">$</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ready</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// request 为一个请求库示例，返回 Promise</span>
    <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">&quot;test&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 获取数据，并填入</span>
      <span class="token function">setPhoneInfo</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>phone_info<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 绑定点击事件</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">&quot;#submit&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;click&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 提取填写的内容并提交</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> phone<span class="token punctuation">,</span> address <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">getPhoneInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 这里也可以进行一些表单验证，此处略</span>
      <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">&quot;test&quot;</span><span class="token punctuation">,</span>
        <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          name<span class="token punctuation">,</span>
          phone<span class="token punctuation">,</span>
          address
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token comment">// 成功后可以清空</span>
        <span class="token function">setPhoneInfo</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
          <span class="token literal-property property">phone</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span>
          <span class="token literal-property property">address</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>所以，其实使用数据驱动还是事件驱动，跟使用 jQuery 还是 Vue 并没有多大关系，只是我们在整个页面的交互过程，从以往的从用户交互为中心，调整成以数据的状态扭转为中心，来进行一些逻辑的实现。</p> <p>但是数据驱动是否又跟 Vue 完全没关系呢？对我个人来说，Vue、Angular、React 这些前端框架的出现，推动了我从事件驱动转变成数据驱动，从而我能更好地使用这些框架。技术的迭代、工具的更新和个人的成长，有时候是相辅相成的。</p> <h4 id="事件流与数据流"><a href="#事件流与数据流" class="header-anchor">#</a> 事件流与数据流</h4> <p>使用数据驱动还有一个好处，就是基于模型设计的代码，即使经历了需求变更、页面结构调整、后台接口调整，也可以快速地实现更新和支持。还是以上面的表单作为例子，我们在基于事件驱动开发，通常的思考和写代码的方式是：</p> <ul><li>页面加载时 -&gt; 请求后台 -&gt; 拿到数据 -&gt; 更新到页面</li> <li>用户点击提交时 -&gt; 获取用户输入内容 -&gt; (校验用户输入内容 -&gt;) 提交给后台 -&gt; 清空已输入内容</li></ul> <p>也就是说，事件驱动的特点是，以某个交互操作为起点，流程式地处理逻辑。流程式的代码，在遇到中间某个环节变更，就需要同时更新该变更点前后环节的流程交接。例如我们在页面加载的时候，需要先加载本地缓存，再从后台请求更新。如果是上面的流程，我们需要新增“本地获取缓存”的环节，同时需要在“页面加载时”、“更新到页面”两个环节进行衔接。</p> <p>而数据驱动的思考方式特点是，以数据为中心，思考数据的输入和输出：</p> <ul><li><code>phoneInfo</code>的数据来源包括两个：从后台获取、用户输入、重置清空</li> <li><code>phoneInfo</code>的数据去处包括：提交给后台</li></ul> <p>同样的，如果我们需新增“本地获取缓存”的环节，在数据驱动的情况下，只是增加了一个数据来源，对于整个模型影响会小很多：</p> <ul><li><code>phoneInfo</code>的数据来源包括两个：<code>从本地缓存获取</code>、从后台获取、用户输入、重置清空</li></ul> <p>其实在我们日常开发中，更多时候是结合了事件驱动和数据驱动来使用。而如果现在的你刚入门没多久，也不用纠结是否真的用了某种思维模式、是否用了什么设计模式，我们在一次次的开发过程中，会不断地积累和加深一些思考，适合自己的才是最好的。</p> <h2 id="_9-2-大型应用管理"><a href="#_9-2-大型应用管理" class="header-anchor">#</a> 9.2 大型应用管理</h2> <p>说到大型应用，常见的我们项目中需要考虑加载性能和加载速度相关的，这些在很多前端相关的文章或者书籍中都可找到。这里主要介绍一些在大型项目中会使用到的工具，以及好用的技巧，还有项目规范、合作开发等经验，供大家参考。</p> <h3 id="_9-2-1-代码打包"><a href="#_9-2-1-代码打包" class="header-anchor">#</a> 9.2.1 代码打包</h3> <p>我们先从最基础的代码打包来讲起。</p> <h4 id="路由懒加载"><a href="#路由懒加载" class="header-anchor">#</a> 路由懒加载</h4> <p>当我们的应用变得很大，为了提升首屏加载的体验，我们需要对代码进行分块打包。一般来说，不同的框架有不同的异步加载解决方案，同时可以结合打包工具（Webpack、Gulp 等）进行分块打包。我们可以把首屏相关的东西打包到 bundle 文件中，其他模块分块打包到 chunk 文件，首页只需要加载 bundle 文件，然后在空闲的时候或者需要使用的时候再按需加载 chunk 文件模块。</p> <p>通常情况下，我们会结合路由进行分块打包，路由管理工具大部分都支持异步加载。我们可以根据自己需要，来打包成多个文件，在路由进入的时候才获取和加载。Vue 可参考<a href="/vue-ebook/vue-ebook/7.html">《第7章 Vue Router 路由搭建应用》</a>中路由懒加载相关内容。</p> <h4 id="source-map"><a href="#source-map" class="header-anchor">#</a> Source Map</h4> <p>这里需要讲一下，Source Map 就是一个信息文件，里面储存着位置信息。也就是说，转换后的代码的每一个位置，所对应的转换前的位置。有了它，我们在定位压缩后的代码时，浏览器可以将直接显示原始代码，而不是压缩后的代码。这无疑给开发者带来了很大的便利。在开发环境下，还能通过 Chrome 匹配源文件进行在线 debug 和修复源码。大家也可以自行搜索下，进行了适当的配置之后，我们可以在浏览器上直接调试 CSS 并保存到本地文件，体验真的很棒。</p> <h4 id="tree-shaking"><a href="#tree-shaking" class="header-anchor">#</a> Tree-shaking</h4> <p>我们在引入一些开源代码或是公共库的时候，其实大部分时间我们都只是使用其中里面的一小部分代码。Tree-shaking 支持按需打包，没有被引用的模块不会被打包进来，减少我们的包大小，缩小应用的加载时间，给用户更好的体验。</p> <p>Tree-shaking 最初是<a href="http://www.rollupjs.com/" target="_blank" rel="noopener noreferrer">Rollup<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>提出并实现。Rollup 会静态分析代码中的 import，并将排除任何未实际使用的代码。这允许我们架构于现有工具和模块之上，而不会增加额外的依赖或使项目的大小膨胀。在 Webpack 2 里也加入了 Tree-shaking 新特性，而 Vue 3.0 中也对支持 Tree-shaking 进行了优化，降低了代码包大小，可以参考<a href="/vue-ebook/vue-ebook/16.html">《第16章 关于 Vue 3.0》</a>。</p> <h3 id="_9-2-2-抽象、组件化和配置化"><a href="#_9-2-2-抽象、组件化和配置化" class="header-anchor">#</a> 9.2.2 抽象、组件化和配置化</h3> <p>在我们开始写重复的代码、或是进行较多的复制粘贴的时候，大概是时候需要考虑对组件进行适当的抽象（也可以成为封装）了。好的抽象能大量减少重复代码，同时对项目整体有更深入的理解。过度的抽象会增加项目的复杂度，同时降低了代码的可读性和维护性。所以关键在于适度，好的办法是结合产品和业务来进行抽象，例如一个播放器组件、日历组件、快速导航栏、快捷菜单等组件封装，便于多次使用。</p> <p>应用的抽象、配置化相关，可以参考<a href="/vue-ebook/vue-ebook/10.html">《第10章 如何正确地进行抽象》</a>和<a href="/vue-ebook/vue-ebook/13.html">《第13章 实战：表单配置化实现》</a>。同时，我们也需要把一些相同的方法抽离，封装成通用的工具库，像常用的时间转换、字符串处理、http 请求等，都可以单独拎出来维护。</p> <h3 id="_9-2-3-状态和数据管理"><a href="#_9-2-3-状态和数据管理" class="header-anchor">#</a> 9.2.3 状态和数据管理</h3> <p>我们的应用里，多数会面临组件的某些状态和数据相互影响、相互依赖的问题。现在也有比较成熟的解决方案和状态管理工具，像 Vuex、Redux、Mobx 等，我们需要结合自身的框架和业务场景来使用。像父子组件的交互、应用内无直接管理的数据状态共享、事件的传递等，也都需要结合实际适当地使用，可参考<a href="/vue-ebook/vue-ebook/11.html">《第11章 全局数据管理与 Vuex》</a>。</p> <h3 id="_9-2-4-代码流程规范"><a href="#_9-2-4-代码流程规范" class="header-anchor">#</a> 9.2.4 代码流程规范</h3> <p>代码规范其实是团队合作中最重要的地方，使用统一的代码规范，会大大减少我们接手别人代码时候感觉到头疼的次数。好的代码习惯很重要，命名、适当的注释、适度的抽象等，会对代码的可读性有很大的提升。但是问题是每个人习惯都不一样，所以在此之上，我们需要有统一的代码规范。由于每个人习惯不一致，所以不可能让所有人都满意，代码规范的存在本身就已经有很重要的作用了。</p> <h4 id="项目结构"><a href="#项目结构" class="header-anchor">#</a> 项目结构</h4> <p>项目结构其实也很重要，我们在设计一个项目的时候，项目结构设计得清晰，维护就会越方便。项目结构设计有几个技巧：</p> <ul><li>公共库、公共组件、公共配置分开维护</li> <li>静态资源文件单独放</li> <li>与构建相关的配置文件，可以放在最外层</li> <li>最后打包生成的文件，可以放在 dist 或者 built 目录下</li> <li>README.md 文件放在最外层</li></ul> <p>在 Vue 中，我们可以这么组织：</p> <div class="language- extra-class"><pre class="language-text"><code>├─dist                      // 编译之后的项目文件
├─src                       // 开发目录
│  ├─assets                 // 静态资源
│     ├─css		              // 公共css
│     ├─img					        // 图片资源
│  ├─utils                  // 公共工具库
│  ├─config                 // 公共配置
│  ├─components             // 公共组件
│  ├─pages                  // 页面，根据路由结构划分
│  ├─App.vue                // 启动页面，最外层容器组件
│  ├─main.js                // 入口脚本
│
├─ babel.config.js          // babel 配置文件
├─ vue.config.js            // vue 自定义配置，与 webpack 配置相关
├─ package.json             // 项目配置
├─ README.md                // 项目说明
</code></pre></div><p>同时，这样的结构可以写在 README 文件中维护，在协作过程、新人加入的时候就可以直接清晰地理解项目代码，也可以快速地找到需要的文件放置在哪里。而 README 在项目管理中也是很重要的一个文档，我们也来看看。</p> <h4 id="养成写-readme-的习惯"><a href="#养成写-readme-的习惯" class="header-anchor">#</a> 养成写 README 的习惯</h4> <p>一般来说，程序员拿到一个项目，首先要找一下文档。而程序员的文档基本上都是用 README 来管理的，一般来说 README 里面会包括：</p> <ul><li>项目简单说明（背景、相关接口人）</li> <li>如何运行代码（安装、启动、构建）</li> <li>目录结构说明</li> <li>更多其他相关说明（配置文件、涉及文档）</li></ul> <p>如果涉及文档太多，也可以统一放置在 docs 文件夹下面。这样，新人在接手到这个项目的时候，可以根据 README 中的指引自行进行代码下载和运行，也可以快速地找到相关的指引和责任人。</p> <h4 id="代码流程规范工具"><a href="#代码流程规范工具" class="header-anchor">#</a> 代码流程规范工具</h4> <p>一些工具可以很好地协助我们，像 Eslint、Tslint 等（目前 Tslint 已不再维护，可以使用 Eslint），加上代码的打包工具协助，可以在一些流程中强校验代码规范。还可以使用像 prettier 这样的工具，能自动在打包的时候帮我们进行代码规范化。</p> <p>除了这些简单的什么驼峰、全等、单引双引等基础的规范，其实更重要的是<strong>流程规范</strong>。最基础的比如改动公共库或是公共组件的时候，需要进行 code review。通常我们使用 Git 维护代码，通过 merge request 等方式来进行 code review，这样在合并或是版本控制上有更好的体验。但其实最重要的还是沟通，沟通是一个团队里必不可少、同时又很容易出问题的地方。</p> <p>项目的维护永远是程序员的大头，一般来说前人种树后人乘凉。但是很多时候，大家会为了一时的方便，对代码规范比较随意，就导致了我们经常看到有人讨论“继承”来的代码，就变成了了前人挖坑后人填坑的方式了。或许相比新技术的研究和造轮子，有个好的写码习惯、提高项目维护性并不能带来短期的利益，但是其实身为一个负责任的程序员，还是要对有些追求的。</p> <p>项目管理和维护其实是很重要的一件事，但这些在日常工作中常常会被忽视。更多人的关注点在系统上线，而运营和维护其实也是同样有价值和有作业的工作，我们也应该重视起来。</p> <p>互联网在不断地发展，新技术层出不穷，处在叶子尖端的前端领域更是在不断摇晃。我们在一个陌生环境中，会习惯性用最熟悉的行为来继续。但如果以开放的心态来接受新事物，你会有想象不到的收获。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/vue-ebook/edit/ebook-sourcecode/docs/vue-ebook/9.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本书采用“保持署名—非商用”<a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">创意共享4.0许可证</a>。只要保持原作者署名和非商用，您可以自由地阅读、分享、修改本书。</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/vue-ebook/vue-ebook/8.html" class="prev">
          第8章 实战：Todo List 从组件到应用
        </a></span> <span class="next"><a href="/vue-ebook/vue-ebook/10.html">
          第10章 如何正确地进行抽象
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-4760" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/vue-ebook/assets/js/app.a856ee15.js" defer></script><script src="/vue-ebook/assets/js/2.2a4d101b.js" defer></script><script src="/vue-ebook/assets/js/3.9083e877.js" defer></script><script src="/vue-ebook/assets/js/23.46caffca.js" defer></script>
  </body>
</html>
